﻿using AntdUI;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OperateMouse
{
    public partial class FrmOpencv : BaseForm
    {
        /// <summary>
        /// 
        /// </summary>
        private bool _isStart = false;
        private int _x = 0;
        private int _y = 0;
        private int _width = 0;
        private int _height = 0;
        private int _time = 5000;
        private string _path = "";
        private double _ratio = 0.9;
        private bool _isShutdown = false;
        /// <summary>
        /// 是否关闭
        /// </summary>
        private bool _isClose = false;
        public FrmOpencv()
        {
            InitializeComponent();

            string path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "config.db");
            if (File.Exists(path))
            {
                string json = File.ReadAllText(path);
                ConfigModule config = JsonSerializer.Deserialize<ConfigModule>(json)!;
                txtHeight.Text = config.Height.ToString();
                txtPath.Text = config.Path;
                txtRatio.Text = config.Ratio.ToString();
                txtTime.Text = config.Time.ToString();
                txtWidth.Text = config.Width.ToString();
                txtX.Text = config.X.ToString();
                txtY.Text = config.Y.ToString();
                chkIsShutdown.Checked = config.IsShutdown;
            }
        }

        private void FrmOpencv_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!_isClose)
            {
                this.Hide();
                e.Cancel = true;
            }
        }
        /// <summary>
        /// 单击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void nfiTool_Click(object sender, EventArgs e)
        {
            if (e is MouseEventArgs mouse && mouse.Button == MouseButtons.Right)
            {
                var menulist = new IContextMenuStripItem[]
                {
                    new ContextMenuStripItem("显示界面"),
                    new ContextMenuStripItem("退出程序")
                };
                AntdUI.ContextMenuStrip.open(this, nfiTool, it =>
                {
                    if (it.Text == "显示界面")
                    {
                        this.Show();
                    }
                    else if (it.Text == "退出程序")
                    {
                        _isClose = true;
                        this.Close();
                    }
                }, menulist);
            }
            else
            {
                this.Show();
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                if (!int.TryParse(txtX.Text, out int x))
                {
                    return;
                }
                if (!int.TryParse(txtY.Text, out int y))
                {
                    return;
                }
                if (!int.TryParse(txtWidth.Text, out int width))
                {
                    return;
                }
                if (!int.TryParse(txtHeight.Text, out int height))
                {
                    return;
                }
                if (!int.TryParse(txtTime.Text, out int time))
                {
                    return;
                }
                if (!double.TryParse(txtRatio.Text, out double dblRatio))
                {
                    return ;
                }
                if (!Directory.Exists(txtPath.Text))
                {
                    return;
                }
                _x = x;
                _y = y;
                _height = height;
                _width = width;
                _isStart = true;
                _path = txtPath.Text;
                _time = time;
                _ratio = dblRatio;
                _isShutdown = chkIsShutdown.Checked;
                ConfigModule configModule= new ConfigModule()
                {
                    Height = _height,
                    Width = _width,
                    X = _x,
                    Y = _y,
                    Path = _path,
                    Ratio = _ratio,
                    Time = _time,
                    IsShutdown = _isShutdown,
                };

                string path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "config.db");
                string text = JsonSerializer.Serialize(configModule);
                File.WriteAllText(path, text);

                btnStart.Enabled = false;
                btnStop.Enabled = true;
                Task.Run(Start);
            }
            catch (Exception exc)
            {
                AntdUI.Message.error(this, exc.Message);
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            _isStart = false;
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }
        private async Task Start()
        {
            while (_isStart)
            {
                try
                {
                    using (Bitmap img = GetImage())
                    {
                        MemoryStream memoryStream = new MemoryStream();
                        img.Save(memoryStream, ImageFormat.Png);
                        memoryStream.Flush();
                        var big = memoryStream.ToArray();
                        memoryStream.Close();
                        var files = Directory.GetFiles(_path, "*.png");
                        double dblMaxRatio = 0;
                        string fileName = "";
                        for (int i = 0; i < files.Length; i++)
                        {
                            string name = Path.GetFileName(files[i]);
                            var small = File.ReadAllBytes(files[i]);
                            double ratio = CVMatch(big, small, _ratio);
                            if (ratio > dblMaxRatio)
                            {
                                dblMaxRatio = ratio;
                                fileName = name;
                            }
                        }
                        if (string.IsNullOrEmpty(fileName))
                        {
                            continue;
                        }
                        Trace.WriteLine(fileName+"" +dblMaxRatio);
                        if (fileName.StartsWith("stop_"))
                        {
                            BeginInvoke(btnStop_Click, null,null);
                            // 自动关机
                            if (_isShutdown)
                            {
                                Process.Start("shutdown", "/s /t 0");
                            }
                            break;
                        }
                        // 获取点击坐标
                        var arr = fileName.Split('_');
                        if (arr.Length != 4)
                        {
                            continue;
                        }
                        int x = Convert.ToInt32(arr[1]);
                        int y = Convert.ToInt32(arr[2]);
                        //点击
                        MouseHookHelper.SetCursorPos(x, y);
                        MouseHookHelper.mouse_event(MouseHookHelper.MOUSEEVENTF_LEFTDOWN, x * 65536 / Screen.PrimaryScreen.Bounds.Width,
                            y * 65536 / Screen.PrimaryScreen.Bounds.Height, 100, 0);
                        MouseHookHelper.mouse_event(MouseHookHelper.MOUSEEVENTF_LEFTUP, 500 * 65536 / Screen.PrimaryScreen.Bounds.Width,
                            500 * 65536 / Screen.PrimaryScreen.Bounds.Height, 100, 0);
                    }
                }
                catch (Exception exc)
                {
                    AntdUI.Notification.error(this, "执行异常", exc.Message);
                }
                finally
                {
                    await Task.Delay(_time);
                }
            }
        }
        /// <summary>
        /// 图片匹配
        /// </summary>
        /// <param name="bytesBig"></param>
        /// <param name="bytesSmall"></param>
        /// <param name="threshold"></param>
        public double CVMatch(byte[] bytesBig, byte[] bytesSmall, double threshold = 0.8)
        {
            double dblMaxRatio = 0;
            var refMat = Mat.FromImageData(bytesBig, ImreadModes.AnyColor);//大图
            var tplMat = Mat.FromImageData(bytesSmall, ImreadModes.AnyColor);//小图
            using (Mat res = new Mat(refMat.Rows - tplMat.Rows + 1, refMat.Cols - tplMat.Cols + 1, MatType.CV_32FC1))
            {
                Cv2.MatchTemplate(refMat, tplMat, res, TemplateMatchModes.CCoeffNormed);
                Cv2.Threshold(res, res, 0.8, 1.0, ThresholdTypes.Tozero);

                byte[] maskBytes = new byte[res.Rows * res.Cols];
                while (true)
                {
                    Cv2.MinMaxLoc(res, out var minval, out var maxval, out var minloc, out var maxloc);
                    if (maxval >= threshold)
                    {
                        // 获取到小图坐标
                        // maxloc.X;maxloc.Y;
                        dblMaxRatio = maxval;
                    }
                    break;
                }
            }
            refMat.Dispose();
            tplMat.Dispose();
            return dblMaxRatio;
        }
        private Bitmap GetImage()
        {
            // 创建一个 Bitmap 对象，大小为屏幕的大小
            Bitmap bitmap = new Bitmap(_width, _height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(_x, _y, 0, 0, bitmap.Size);
            }
            return bitmap;

        }
    }
}
